/***************************************************************************
 *   Copyright (C) 2006 by Harish Kukreja                                  *
 *   harish.kukreja@gmail.com                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//
// C++ Interface: computations
//
// Description: Headers for miscellaneous computation functions used in Physiks. Also includes
//              prototypes for functions that modify the states of PhysicalObjects according to
//              fields.
//
// Author: Harish Kukreja <harish.kukreja@gmail.com>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//


#ifndef _COMPUTATIONS_H_
#define _COMPUTATIONS_H_

#include <physiksbase/objects.h>
#include <physiksbase/physiksvector.h>
#include <gsl/gsl_blas.h>
#include <gsl/gsl_const_mksa.h>
#include <gsl/gsl_math.h>
#include <vector>

namespace PhysiksBase {
    namespace Computation {
        using std::vector;
        using PhysiksBase::PhysicalObject;
        
        /** \brief Applies each force field specified in the 2nd parameter to all objects in the
         *         given object table.
         * \param objTable   an object table containing pointers to the objects to be updated
         * \param force_fields   all force fields to be applied to each object in objTable  */
        void apply_force_fields(vector<PhysicalObject *> &objTable,
                                const vector<ForceField *> &force_fields);
        
        /** \brief Applies each acceleration field specified in the 2nd parameter to all objects in
         *         the given object table.
         * \param objTable   an object table containing pointers to the objects to be updated
         * \param force_fields   all acceleration fields to be applied to each object in objTable
         */
        void apply_acceleration_fields(vector<PhysicalObject *> &objTable, 
                                       const vector<AccelerationField *> &accel_fields);

        /** \brief Applies each velocity field specified in the 2nd parameter to all objects in the
         *         given object table. */
        void apply_velocity_fields(vector<PhysicalObject *> &objTable, 
                                   const vector<VelocityField *> &vel_fields);
        
        /** \brief Computes the distance between two physical objects in Cartesian-Euclidean space.
         * @param a object a
         * @param b object b
         * @return the scalar distance between a and b */
        double compute_distance(const PhysicalObject &a, const PhysicalObject &b);
        
        Vector compute_connecting_vector(const PhysicalObject &a, const PhysicalObject &b);

        /** \brief Sets the force vectors of all objects in objTable to the zero vector.
         * @param objTable the object table containing pointers to the relevant objects */
        void set_force_vectors_zero(vector<PhysicalObject *> &objTable);

        /** \brief Updates the force vectors of all objects in objTable based on built-in force
         *         fields, and user-defined fields. */
        void update_forces(vector<PhysicalObject *> &objTable);

        /** \brief Updates the velocity vectors of all objects in objTable based on their force
         *         vectors.
         * @param time_step the time interval in the equation v = v_0 + a*t */
        void update_velocities(vector<PhysicalObject *> &objTable, double time_step);

        /** \brief Updates the position vectors of all objects in objTable based on their net force
         *         and velocity vectors.
         * @param time_step the time interval in the equation s = s_0 + v_0*t + 0.5*a*t^2 */
        void update_positions(vector<PhysicalObject *> &objTable, double time_step);

        /** \brief Computes the Newtonian gravitational force between two objects.
         * @return the magnitude of the gravitational force between obj1 and obj2 */
        double compute_gravitational_force(const PhysicalObject &obj1, const PhysicalObject &obj2);

        /** \brief Calculates the signed magnitude of the coulomb force between two charges.
         * @param a Object a
         * @param b Object b
         * @return the signed magnitude of the Coulomb force between charges a & b */
        double compute_coulomb_force(const PhysicalObject &obj1, const PhysicalObject &obj2);
    }
}

#endif
